package com.object.oriented.exam.system3.entity.dto;

import com.object.oriented.exam.system1.entity.Problem;
import lombok.Data;
import lombok.NoArgsConstructor;

import com.object.oriented.exam.system3.entity.po.Paper;
import java.util.*;

/**
 * 种群
 */
@Data
@NoArgsConstructor
public class Population {

    private List<Paper> paperList;

    public Population(int populationSize, Map<Integer,List<Problem>> typeMap, SurveyRuleParam surveyRuleParam,int kNum,double difficultyRatio,double knowledgeRatio) {
        this.paperList = new ArrayList<>();

        //设置初始生态
        for (int i = 0; i < populationSize; i++) {
            Paper paper = new Paper();
            for(Integer type : surveyRuleParam.getTypesNum().keySet()){
                //拼接当前题目
                generateQuestion(type,surveyRuleParam.getTypesNum().get(type),typeMap.get(type),paper);
            }
            //计算试卷的适应度
            paper.calculateAdaptationDegree(surveyRuleParam,kNum,difficultyRatio,knowledgeRatio);
            //加入生态
            this.paperList.add(paper);
        }

    }

    //添加问题到问卷
    private void generateQuestion(int type,int questionNum,List<Problem> typeList,Paper paper){
        if(questionNum > typeList.size()){
            throw new RuntimeException("problem is not enough to create the paper");
        }
        Random random = new Random();
        for(int i = 0; i < questionNum; i++){
            int range = typeList.size() - i;
            if(range < 0){
                //数据库符合要求的题目太少了 或者直接抛异常
                throw new RuntimeException("problem is not enough to create the paper");
            }
            int index = random.nextInt(range);

            //试卷中没有该题目
            Problem problem = typeList.get(index);
            if(!paper.containProblem(problem)){
                //添加到问卷的题目组中
                paper.addProblem(problem);
            }
            Collections.swap(typeList,index,typeList.size() - i - 1);
        }
    }

    public Paper getFitness() {
        Paper paper = this.paperList.get(0);
        for(Paper tempPaper : paperList){
            if(paper.getAdaptationDegree() < tempPaper.getAdaptationDegree()){
                paper = tempPaper;
            }
        }
        return paper;
    }
}
